package com.example.tianling.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.tianling.WebSocket.handler.TrainWebSocketHandler;
import com.example.tianling.WebSocket.handler.UserWebSocketHandler;
import com.example.tianling.common.annotation.Login;
import com.example.tianling.common.annotation.LoginUser;
import com.example.tianling.common.params.*;
import com.example.tianling.common.utils.R;
import com.example.tianling.common.utils.ScheduledTask;
import com.example.tianling.common.utils.WsMessage;
import com.example.tianling.common.vo.FriendVo;
import com.example.tianling.common.vo.TrainListVo;
import com.example.tianling.dao.MatchMapper;
import com.example.tianling.entity.*;
import com.example.tianling.service.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.text.ParseException;
import java.util.*;

@Controller
public class RoomController {
    @Autowired
    private UserService userService;

    @Autowired
    private RoomService roomService;

    @Autowired
    private RoomUserService roomUserService;

    @Autowired
    private MatchService matchService;

    @Autowired
    private BookService bookService;

    @Autowired
    private MessageService messageService;

    @Autowired
    private UserWebSocketHandler userWebSocket;

    @Autowired
    private TrainWebSocketHandler trainWebSocket;

    @Autowired
    private ScheduledTask scheduledTask;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private TrainResultService trainResultService;


    /*
     * 加载首页
     * 1.根据token响应user对象
     */
    @Login
    @PostMapping("/index")
    @ResponseBody
    public R index(@LoginUser UserEntity user){
        return R.success(user);
    }

    /*
     * 更新用户状态 controller层
     */
    @Login
    @PostMapping("/index/update_user_state.do")
    @ResponseBody
    public R updateUserState(@RequestBody UpdateUserStateDo updateUserStateDo, @LoginUser UserEntity user){
        userService.updateUserState(updateUserStateDo,user);
        return R.success();
    }


    /*
     * 创建房间 controller层
     * 1.将创建的房间插入room和room_user表
     * 2.根据isMatch判断是否能插入匹配表match
     * 3.封装房间号roomId和userId成功响应
     */
    @Login
    @PostMapping("/room/create_room.do")
    @ResponseBody
    public R createRoom(@RequestBody CreateRoomDo createRoomDo,@LoginUser UserEntity user){
        // 1.将创建的房间插入room和room_user表
        RoomEntity room = roomService.insertRoomByCreate(createRoomDo,user);

        // 3.封装房间号roomId成功响应
        Map<String, Object> map = new HashMap<>();
        map.put("roomId", room.getRoomId());
        map.put("userId", user.getUserId());
        return R.success(map);
    }

    /*
     * 预约房间
     * 1.更新room表
     * 2.预约成功则将房间room封装到成功响应中
     * 3.已预约抛出异常 (code=409, msg="已预约房间")
     */
    @Login
    @PostMapping("/room/reserve_room.do")
    @ResponseBody
    public R reserveRoom(@RequestBody CreateRoomDo createRoomDo,@LoginUser UserEntity user) throws ParseException {
        // 1.更新room表
        RoomEntity room = roomService.insertReserveRoom(createRoomDo,user.getUserId());

        Date reserveTime = room.getStartTime();
        long minutes = (reserveTime.getTime() - new Date().getTime()) / (60 * 1000) % 60;
        scheduledTask.startScheduledTaskByMinute((int) (minutes - 10), new Runnable() {
            @Override
            public void run() {
                // 1.更新room表
                roomService.updateRoomState(room.getRoomId().toString(), 0);
                // 2.更新message表
                messageService.updateStatus(room.getRoomId().toString());
                // 3.发送给预约的用户
                WsMessage reserveMessage = new WsMessage("reserve", room);
                List<ChatMessageEntity> messageList = messageService.getMessagesByRoomId(room.getRoomId().toString());
                for (ChatMessageEntity m : messageList) {
                    try {
                        userWebSocket.sendMessageToOne(m.getToId().toString(), reserveMessage);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }

            }
        });

        // 2.预约成功则将房间room封装到成功响应中
        return R.success(room);
    }

    @Login
    @PostMapping("/room/come_reserve_room.do")
    @ResponseBody
    public R comeReserveRoom(@RequestBody String params, @LoginUser UserEntity user) {
        // 1.Json解析roomId
        JSONObject paramsJSONObject = JSONObject.parseObject(params);
        String roomId = paramsJSONObject.getString("roomId");

        messageService.insertReserveMessage(roomId, user.getUserId());
        return R.success();
    }


    /*
     * 取消预约房间
     */
    @PostMapping("/room/delete_reserve_room.do")
    public R deleteRoom(@RequestBody String params) {
        // 1.Json解析roomId
        JSONObject paramsJSONObject = JSONObject.parseObject(params);
        Integer roomId = Integer.parseInt(paramsJSONObject.getString("roomId"));

        roomService.removeRoom(roomId);
        return R.success();
    }

    /*
     * 进房
     * 1.Json解析roomId,并获取room对象
     * 2.需要更新room和room_user表
     * 3.封装房间号roomId和userId成功响应
     */
    @Login
    @PostMapping("/room/come_room.do")
    @ResponseBody
    public R comeRoom(@RequestBody String params, @LoginUser UserEntity user){
        // 1.Json解析roomId
        JSONObject paramsJSONObject = JSONObject.parseObject(params);
        Integer roomId = Integer.parseInt(paramsJSONObject.getString("roomId"));
        RoomEntity room = roomService.getRoom(roomId);

        if (room == null) {
            // 1.根据roomId查询房间，房间不存在则抛出异常(code=404, msg="房间不存在")
            return R.error(404, "房间不存在");
        } else if (room.getRealNumber().equals(room.getMaxNumber())) {
            // 2.检查人数是否已满，人数已满则抛出异常(code="402", msg="房间人数已满")
            return R.error(402, "房间人数已满");
        }

        if (room.getRoomState() == -1) {
            roomService.updateRoomState(roomId.toString(), 0);
        }

        // 3.封装房间号roomId成功响应
        Map<String, Object> map = new HashMap<>();
        map.put("type", room.getType());
        map.put("roomId",roomId);
        map.put("userId", user.getUserId());
        return R.success(map);
    }

    /*
     * 用户匹配
     * 1.根据用户查询匹配表中相关的房间和用户信息，并按realNumber从大到小排序取最大的match
     * 2.判断match
     *   (1)match为空则将用户信息插入匹配表
     *   (2)match为房间,则更新匹配表match、room、room_user表,向该用户发送匹配成功信息
     *   (3)match为用户,则创建房间room、room_user表、更新匹配表match,向两个用户发送匹配成功信息
     */
//    @Login
//    @PostMapping("/room/start_user_match.do")
//    @ResponseBody
//    public R userMatch(@RequestBody String params, @LoginUser UserEntity user) {
//
//        JSONObject paramsJSONObject = JSONObject.parseObject(params);
//        String type = paramsJSONObject.getString("type");
//
//        try {
//            Map<String, Object> map = new HashMap<>();
//            map.put("type", type);
//            map.put("userId", user.getUserId());
//            rabbitTemplate.convertAndSend("topicExchangeMatch", "topic.match", map);
//        }catch(Exception e){
//            e.printStackTrace();
//        }
//
//        return R.success();
//    }

    // 停止匹配
    @Login
    @PostMapping("/room/stop_user_match.do")
    @ResponseBody
    public R stopUserMatch(@LoginUser UserEntity user) {
        matchService.removeByUserId(user.getUserId());
        return R.success();
    }


    // 开启匹配
    @PostMapping("/room/start_match.do")
    @ResponseBody
    public R startRoomMatch(@RequestBody String params) throws JsonProcessingException {
        JSONObject paramsJSONObject = JSONObject.parseObject(params);
        Integer roomId = paramsJSONObject.getInteger("roomId");
        roomService.updateIsMatch(roomId, 1);
        RoomEntity room = roomService.getRoom(roomId);
        Map<String, Object> map = new HashMap<>();
        map.put("roomInfo", room);
        WsMessage message = new WsMessage<>("startMatch", map);
        trainWebSocket.sendMessageToAll(roomId.toString(), message);

        matchService.insertRoom(room);
        return R.success();
    }

    // 停止匹配
    @PostMapping("/room/stop_match.do")
    @ResponseBody
    public R stopRoomMatch(@RequestBody String params) throws JsonProcessingException {
        JSONObject paramsJSONObject = JSONObject.parseObject(params);
        Integer roomId = paramsJSONObject.getInteger("roomId");
        roomService.updateIsMatch(roomId, 0);
        RoomEntity room = roomService.getRoom(roomId);
        Map<String, Object> map = new HashMap<>();
        map.put("roomInfo", room);
        WsMessage message = new WsMessage<>("stopMatch", map);
        trainWebSocket.sendMessageToAll(roomId.toString(), message);

        matchService.removeByRoomId(roomId);
        return R.success();
    }

    // 允许被合并
    @PostMapping("/room/allow_merge.do")
    @ResponseBody
    public R allowMerge(@RequestBody String params) {
        JSONObject paramsJSONObject = JSONObject.parseObject(params);
        Integer roomId = paramsJSONObject.getInteger("roomId");
        matchService.updateIsMerge(roomId, 1);
        return R.success();
    }

    // 不允许被合并
    @PostMapping("/room/reject_merge.do")
    @ResponseBody
    public R rejectMerge(@RequestBody String params) {
        JSONObject paramsJSONObject = JSONObject.parseObject(params);
        Integer roomId = paramsJSONObject.getInteger("roomId");
        matchService.updateIsMerge(roomId, 0);
        return R.success();
    }
    /*
     * 房间匹配
     * 1.Json解析roomId,并取出room
     * 2.根据room中的area、type、realNumber和maxNumber来查询match
     *   (1)match为空
     *   (2)match不为空，则发送信息给那个房间
     */
    @PostMapping("/room/room_request.do")
    public void roomMatch(@RequestBody String params) throws IOException {
        // 1.Json解析roomId,并取出room
        JSONObject paramsJSONObject = JSONObject.parseObject(params);
        Integer roomId = Integer.parseInt(paramsJSONObject.getString("roomId"));
        RoomEntity room = roomService.getRoom(roomId);

        // 1.根据area、realNumber和maxNumber来查询match
        MatchEntity match = matchService.getMatchByRoom(room);

        // (1)match为空
        if (match == null) {
            return;
        } else if (match.getRoomId() != null){
            trainWebSocket.mergeRoom(roomId.toString(), match.getRoomId().toString());
        }
    }

    @PostMapping("/room/choose_book.do")
    @ResponseBody
    public R chooseBook(@RequestBody String params) {
        JSONObject paramsJSONObject = JSONObject.parseObject(params);
        String type = paramsJSONObject.getString("type");
        String area = paramsJSONObject.getString("area");

        List<BookEntity> bookList = bookService.getBooksByArea(area, type);
        return R.success(bookList);
    }

    @PostMapping("/room/show_book.do")
    @ResponseBody
    public R showBook(@RequestBody String params) {
        JSONObject paramsJSONObject = JSONObject.parseObject(params);
        String bookId = paramsJSONObject.getString("bookId");
        BookEntity book = bookService.getBookByBookId(Integer.parseInt(bookId));
        return R.success(book);
    }

    @Login
    @PostMapping("/room/friend_list")
    @ResponseBody
    public R getFriendList(@LoginUser UserEntity user) {
        List<FriendVo> friendList = messageService.getFriendList(user.getUserId());
        return R.success(friendList);
    }


    @Login
    @PostMapping("/room/train_list")
    @ResponseBody
    public R getTrainList(@LoginUser UserEntity user) {
        List<TrainListVo> trainList = trainResultService.getTrainList(user.getUserId());
        List<TrainListVo> resultList = new ArrayList<>();

        for (TrainListVo trainListVo : trainList) {
            if (trainListVo.getBookName() == null) {
                trainListVo.setBookName("结构化全真模拟");
            }
            resultList.add(trainListVo);
        }
        return R.success(resultList);
    }

    @Login
    @PostMapping("/room/get_result")
    @ResponseBody
    public R getResult(@RequestBody String params, @LoginUser UserEntity user) {
        JSONObject paramsJSONObject = JSONObject.parseObject(params);
        Integer roomId = paramsJSONObject.getInteger("roomId");

        RoomEntity room = roomService.getRoom(roomId);
        BookEntity book = bookService.getBookByBookId(room.getBookId());

        TrainResultEntity myResult = trainResultService.getMyResult(roomId, user.getUserId());
        List<TrainResultEntity> trainResultList = trainResultService.getAllData(roomId);

        int myNum = 0;
        int count = 0;
        List<Integer> personalTime = new ArrayList<>();
        List<Integer> speakNum = new ArrayList<>();
        List<Integer> summaryTime = new ArrayList<>();
        for (TrainResultEntity trainResult : trainResultList) {
            count = count + 1;
            if (trainResult.getUserId().equals(myResult.getUserId())) {
                myNum = count;
            }
            personalTime.add(trainResult.getPersonalTime());
            speakNum.add(trainResult.getDiscussionNum());
            summaryTime.add(trainResult.getSummaryTime());
        }

        Map<String, Object> map = new HashMap<>();
        map.put("content", book.getContent());
        map.put("recordUrl", room.getRecordUrl());
        map.put("myNum", myNum);
        map.put("personalTime", personalTime);
        map.put("speakNum", speakNum);
        map.put("summaryTime", summaryTime);
        map.put("personal", myResult.getPersonal());
        map.put("personalAi", myResult.getPersonalAi());
        map.put("note", myResult.getNote());
        map.put("idea_one", book.getIdeaOne());
        map.put("idea_two", book.getIdeaTwo());
        map.put("idea_three", book.getIdeaThree());
        map.put("startTime", myResult.getStartTime());
        map.put("startType", myResult.getStartType());
        map.put("localPath",myResult.getLocalPath());
        return R.success(map);
    }

    @Login
    @PostMapping("/room/get_structure_result")
    @ResponseBody
    public R getStructureResult(@RequestBody String params, @LoginUser UserEntity user) {
        JSONObject paramsJSONObject = JSONObject.parseObject(params);
        Integer roomId = paramsJSONObject.getInteger("roomId");

        RoomEntity room = roomService.getRoom(roomId);

        TrainResultEntity myResult = trainResultService.getMyResult(roomId, user.getUserId());

        Map<String, Object> map = new HashMap<>();
        map.put("readBookList", myResult.getBookList());
        map.put("recordUrl", room.getRecordUrl());
        map.put("note", myResult.getNote());
        return R.success(map);
    }

    @Login
    @PostMapping("/room/update_note")
    @ResponseBody
    public R updateNote(@RequestBody String params, @LoginUser UserEntity user) {
        JSONObject paramsJSONObject = JSONObject.parseObject(params);
        Integer roomId = paramsJSONObject.getInteger("roomId");
        String note = paramsJSONObject.getString("note");

        trainResultService.updateNote(roomId, user.getUserId(), note);

        return R.success();
    }

    @Login
    @PostMapping("/room/save_record")
    @ResponseBody
    public void saveRecord(@RequestBody String params, @LoginUser UserEntity user) {
        JSONObject jsonObject = JSONObject.parseObject(params);
        Integer roomId = jsonObject.getInteger("roomId");
        String localPath = jsonObject.getString("localPath");
        trainResultService.updateLocalPath(roomId, user.getUserId(), localPath);
    }

}
